import {isEmpty, isString, isNumber, isBoolean, assert, reverseMerge} from "../public"
import Condition from './condition'
import AssociativeCondition from "./associativeCondition"
import JoinBuilder from "./joinBuilder"
import request from "../request/index"

export default class QueryBuilder {
  //表名
  table;
  //条件 eq 等
  conditions = [];
  queryType = 2; // 1表示返回总数, 2表示返回列表数和总数 3,
  multiple = false; //有分页的时候mutiple必须为true
  resField; //返回的字段都是那些
  pagination; //分页的配置
  orders; //排序
  associativeCondition = []; //关联表数组
  paramsType = 1; //参数类型 1为[] 2为table[]
  setParamsType = true; //设置参数类型有两种 1为[] 2为table[]
  joinCondition = []; // join条件
  typeConversion; //类型转换
  group;//分组
  //这个是静态方法，直接调用QueryBuilder.by('user', 2)即可
  static by(jsonData) {
    return new QueryBuilder(jsonData);
  }
  //构造函数 table 表名 queryType 查询类型 paramsType配置参数的类型
  constructor(jsonData) {
    //断言 table不为空并且是字符串
    assert(
      !isEmpty(jsonData.table) && isString(jsonData.table),
      `[ApiJson] 参数table: ${jsonData.table} 非法`
    );
    //断言 queryType不为空并且是数字
    if (jsonData.queryType !== undefined) {
      assert(
        [1, 2, 3].indexOf(queryType) > -1,
        `[ApiJson] 参数queryType: ${jsonData.queryType} 非法, 必须为数值1,2,3`
      );
      //给自身的queryType赋值
      this.queryType = jsonData.queryType;
    }
    if (jsonData.paramsType !== undefined) {
      assert(
        [1, 2].indexOf(jsonData.paramsType) > -1,
        `[ApiJson] 参数paramsType: ${jsonData.paramsType} 非法, 必须为数值1,2,3`
      );
      //给自身的paramsType赋值
      this.paramsType = jsonData.paramsType;
    }
    //给自身的table赋值
    this.table = jsonData.table;
  }

  /**
   * 设置关联条件
   * @param table 关联的主表表名
   * @param primaryKey 关联的主表主键
   * @param foreignKey 和主表关联的当前表的外键。可以只输入字段名，或者符合apijson的外键全路径(以/开头)
   * @param resField 关联的主表响应字段
   */
  setAssociativeCondition({
    table,
    primaryKey,
    foreignKey,
    resFields,
    paramsType,
  }) {
    //断言 foreignKey不为空并且是字符串
    if (!isEmpty(foreignKey) && !foreignKey.startsWith("/")) {
      //把外键的路径拼接上当前表的表名
      foreignKey = "/" + this.table + "/" + foreignKey;
    }
    //给自身的associativeCondition数组添加一个关联条件
    this.associativeCondition.push(
      AssociativeCondition.by({ table, primaryKey, foreignKey, resFields })
    );
    if (paramsType !== undefined) {
      assert(
        isBoolean(paramsType),
        `[ApiJson] 参数paramsType: ${paramsType} 非法, 必须为Boolean类型`
      );
    }
    this.setParamsType = paramsType;
    return this;
  }

  /**
   * 设置关联条件
   * @param condition
   * @returns {QueryBuilder}
   */
  setAssociativeConditionPlus(condition) {
    //断言 condition是AssociativeCondition类型
    assert(
      condition instanceof AssociativeCondition,
      `[ApiJson] 参数condition: ${condition} 非法, 必须是 AssociativeCondition类型`
    );
    //给自身的associativeCondition数组添加一个关联条件
    this.associativeCondition.push(condition);
    return this;
  }
  //设置条件
  condition(condition) {
    //断言 condition是Condition类型
    assert(
      condition instanceof Condition,
      `[ApiJson] 参数condition: ${condition} 非法, 必须是 Condition类型`
    );
    //给自身的conditions数组添加一个条件
    this.conditions.push(condition);
    return this;
  }
  //设置join条件
  setJoin(jsonData) {
    this.joinCondition.push(JoinBuilder.by(jsonData));
    return;
  }
  //类型转换
  setTypeConversion(value) {
    assert(
      !isEmpty(value) && isString(value),
      `[ApiJson] 参数value: ${value} 非法, 必须为String类型`
    );
    this.typeConversion = value;
    return this;
  }
  //设置组
  setGroup(groups) {
    assert(
      !isEmpty(groups) && isString(groups),
      `[ApiJson] 参数groups: ${groups} 非法`
    );
    this.group = groups;
    return this;
  }
  //设置返回字段
  setResFields(fields = "*") {
    //断言 fields不为空并且是字符串
    assert(
      !isEmpty(fields) && isString(fields),
      `[ApiJson] 参数fields: ${fields} 非法`
    );

    if (fields.trim() !== "*") {
      this.resField = fields;
    }
    return this;
  }

  multi(multi = false) {
    this.multiple = multi;
    return this;
  }

  page({ page = 0, count = 10 }) {
    assert(
      isNumber(page) && isNumber(count),
      `[ApiJson] 参数page: ${page} 和 count: ${count} 都必须为Number类型`
    );
    this.pagination = {
      page: page,
      count: count,
    };
    return this;
  }

  /**
   *
   * @param field
   * @param desc 是否降序, 默认true
   */
  order({ field, desc = true }) {
    assert(
      !isEmpty(field) && isString(field),
      `[ApiJson] 参数field: ${field} 非法`
    );
    assert(isBoolean(desc), `[ApiJson] 参数desc: ${desc} 非法`);

    this.orders = {};
    this.orders[field] = desc ? "-" : "+ ";
    return this;
  }

  toJson() {
    let json = {};
    const {
      table,
      conditions,
      pagination,
      resField,
      orders,
      multiple,
      associativeCondition,
      queryType,
      joinCondition,
      typeConversion,
      group,
    } = this;

    assert(
      !(pagination && multiple === false),
      "指定了分页内容, 则必须指定multiple为true!"
    );
    //拼接基础配置
    function tableToJson(table, conditions, resField, orders) {
      const tableJson = {};
      if (conditions && conditions.length > 0) {
        conditions.forEach((c) => {
          const json = c.toJson();
          if (json !== null) {
            reverseMerge(tableJson, c.toJson());
          }
        });
      }
      if (resField) {
        tableJson["@column"] = resField; // id内置
      }
      if (typeConversion) {
        tableJson["@cast"] = typeConversion;
      }
      if (orders) {
        tableJson["@order"] = Object.keys(orders)
          .map((field) => field + orders[field])
          .join(",");
      }
      const json = {};
      json[table] = tableJson;
      return json;
    }
    //关联表配置
    function associativeTableToJson(associativeCondition, json) {
      associativeCondition.forEach((c) => {
        reverseMerge(json, c.toJson());
      });
    }
    //join表配置
    function joinTableToJson(joinCondition, json) {
      json.join = "";
      joinCondition.forEach((c) => {
        json.join += c.toJson() + ",";
      });
      //去掉最后的,
      json.join = json.join.slice(0, json.join.length - 1);
    }
    function groupTableToJson(group,json) {
      json["@group"] = group;
    } 
    //分页配置
    if (multiple) {
      let name = `${table}[]`;
      if (this.paramsType === 2) {
        name = "[]";
      }
      json[name] = tableToJson(table, conditions, resField, orders);
      //如果设置了参数类型关联传入的类型 true为table[] false为table
      if (this.setParamsType) {
        associativeTableToJson(associativeCondition, json[name]);
      } else {
        associativeTableToJson(associativeCondition, json);
      }
      //分页配置
      if (pagination) {
        reverseMerge(json[name], pagination);
        json[name]["query"] = queryType; // 查询数据和总数(附带total表示总数) // https://vincentcheng.github.io/apijson-doc/zh/grammar.html#%E5%88%86%E9%A1%B5
        json["pageinfo@"] = "/[]/info";
      }
      if (joinCondition.length > 0) {
        joinTableToJson(joinCondition, json[name]);
      }
      if(group){
        groupTableToJson(group,json[name]);
      }
    } else {
      json = tableToJson(table, conditions, resField, orders);
      associativeTableToJson(associativeCondition, json);
      if (joinCondition.length > 0) {
        joinTableToJson(joinCondition, json);
      }
    }

    return json;
  }

  send(jsonData) {
    const params = this.toJson();
    // return request({
    //     url: '/get',
    //     method: 'post',
    //     data: params
    // })
    return request({
      url: jsonData.url,
      method: jsonData.method ? jsonData.method : "post",
      data: params,
      baseURL: jsonData.baseUrl,
      //如果是下载文件，需要设置responseType: 'blob'
      responseType: jsonData.responseType ? jsonData.responseType : "json",
    });
  }
}